#include "beep.h"
#include "delay.h"

//////////////////////////////////////////////////////////////////////////////////	 
//本程序只供学习使用，未经作者许可，不得用于其它任何用途
//ALIENTEK 精英STM32开发板
//蜂鸣器驱动代码	   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2012/9/2
//版本：V1.0
//版权所有，盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved									  
////////////////////////////////////////////////////////////////////////////////// 	   

//初始化PB8为输出口.并使能这个口的时钟		    
//蜂鸣器初始化
void BEEP_Init(void)
{
 
 GPIO_InitTypeDef  GPIO_InitStructure;
 	
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	 //使能GPIOB端口时钟
 
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;				 //BEEP-->PB.8 端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	 //速度为50MHz
 GPIO_Init(GPIOB, &GPIO_InitStructure);	 //根据参数初始化GPIOB.8
 
 GPIO_ResetBits(GPIOB,GPIO_Pin_8);//输出0，关闭蜂鸣器输出

}

// 外部有源蜂鸣器
void ExtActiveBuzzerInit()
{
    GPIO_InitTypeDef  GPIO_InitStructure;
        
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);	 //使能GPIOE端口时钟
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;				 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	 //速度为50MHz
    GPIO_Init(GPIOE, &GPIO_InitStructure);	 //根据参数初始化
    
    GPIO_ResetBits(GPIOE, GPIO_Pin_2);//输出0，关闭蜂鸣器输出
}

void SetExtActiveBuzzerGPIO(uint8_t status)
{
    if(status)
    {
        GPIO_SetBits(GPIOE, GPIO_Pin_2);
    }
    else
    {
        GPIO_ResetBits(GPIOE, GPIO_Pin_2);
    }
}


void ExtPassiveBuzzerInit()
{
	GPIO_InitTypeDef  GPIO_InitStructure;
        
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);	    //使能GPIOE端口时钟
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;	                //BEEP 端口配置
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		    //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	        //速度为50MHz
    GPIO_Init(GPIOE, &GPIO_InitStructure);	                    //根据参数初始化

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_Init(GPIOE, &GPIO_InitStructure);

}


void ExtPassiveBuzzerPWMInit()
{
    GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;

    // 使用PA6，做TIM3_CH1
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    //设置该引脚为复用输出功能,输出TIM3 CH1的PWM脉冲波形	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; 			//TIM_CH1
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  	//复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);				//初始化GPIO

    
    //初始化TIM3
	TIM_TimeBaseStructure.TIM_Period = 35999; 			//设置在下一个更新事件装入活动的自动重装载寄存器周期的值
	TIM_TimeBaseStructure.TIM_Prescaler = 0; 			//设置用来作为TIMx时钟频率除数的预分频值 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; 		//设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 	//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	
	//初始化TIM3 Channel1 PWM模式	 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 				//选择定时器模式:TIM脉冲宽度调制模式
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 	//比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 		//输出极性:TIM输出比较极性高
	TIM_OC1Init(TIM3, &TIM_OCInitStructure);  						//根据T指定的参数初始化外设TIM3
 
	TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR1上的预装载寄存器
 
	TIM_Cmd(TIM3, ENABLE);  //使能TIM3

}


/*
    Advance
*/

// 音符频率表 (Hz)
const uint16_t notes[] = {
    0,    // 休止符
    262,  // C4 (Do)
    294,  // D4 (Re)
    330,  // E4 (Mi)
    349,  // F4 (Fa)
    392,  // G4 (Sol)
    440,  // A4 (La)
    494,  // B4 (Si)
    523   // C5 (Do高八度)
};


void ExtPassiveBuzzerAdvancePWMInit(uint32_t frequency)
{
    GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;

    // 计算自动重装载值和预分频值
    uint32_t timer_clock = 72000000;  // 72MHz
    uint16_t psc = 1;
    uint16_t arr;

    // 使用PA6，做TIM3_CH1
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    //设置该引脚为复用输出功能,输出TIM3 CH1的PWM脉冲波形	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; 			//TIM_CH1
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  	//复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);				//初始化GPIO


    //初始化TIM3
    // 计算自动重装载值，确保不超过16位
    arr = timer_clock / (frequency * psc);
    if (arr > 65535) 
    {
        psc = timer_clock / (65535 * frequency) + 1;
        arr = timer_clock / (frequency * psc);
    }
    
	TIM_TimeBaseStructure.TIM_Period = arr; 			//设置在下一个更新事件装入活动的自动重装载寄存器周期的值
	TIM_TimeBaseStructure.TIM_Prescaler = psc-1; 			//设置用来作为TIMx时钟频率除数的预分频值 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; 		//设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 	//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	
	//初始化TIM3 Channel1 PWM模式	 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 				//选择定时器模式:TIM脉冲宽度调制模式
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 	//比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 		//输出极性:TIM输出比较极性高
	TIM_OC1Init(TIM3, &TIM_OCInitStructure);  						//根据T指定的参数初始化外设TIM3
 
	TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR1上的预装载寄存器
 
	TIM_Cmd(TIM3, ENABLE);  //使能TIM3

    // 设置初始占空比为50%
    TIM_SetCompare1(TIM3, arr / 2);

}


// 播放单个音符
void PlayNote(uint8_t note_index, uint8_t beat)
{
    uint16_t frequency;
    if (note_index > 8) return;  // 确保索引有效
    
    frequency = notes[note_index];
    
    if (frequency > 0) {
        // 初始化PWM频率
        ExtPassiveBuzzerAdvancePWMInit(frequency);
    } else {
        // 休止符: 关闭PWM输出
        TIM_SetCompare1(TIM3, 0);
    }
    
    // 播放指定节拍 (1拍 = 100ms)
    delay_ms(beat * 100);
}

// 播放音乐
void PlayMusic(const Music_t* music)
{
    uint8_t i;
    for (i = 0; i < music->length; i++) 
    {
        PlayNote(music->melody[i], music->duration[i]);
    }
    
    // 播放结束，关闭蜂鸣器
    TIM_SetCompare1(TIM3, 0);
}
